module controller.SearchController;

import std.json : JSONValue;

import archttp.HttpRequest : HttpRequest;
import archttp.HttpResponse : HttpResponse;
import archttp.HttpStatusCode : HttpStatusCode;

import mir.ser.json : serializeJson;

import model.Teleplay;
import model.TeleplayVlink;
import model.Movie;
import model.MovieVlink;
import model.Animation;
import model.AnimationVlink;
import repository.TeleplayRepo;
import repository.MovieRepo;
import repository.AnimationRepo;

import utils.ObjMapping : ObjMapping;
import utils.RespData : RespData;
import utils.DataCache;
import utils.CacheKey : CacheKey;
import utils.SecurityVerification : signValidator;

// import std.stdio;

/** 
 * 搜索控制器
 */
class SearchController
{
    TeleplayRepo _tRepo; // 电视剧仓储
    MovieRepo _mRepo; // 电影仓储
    AnimationRepo _aRepo; // 动漫仓储
    this ()
    {
        _tRepo = new TeleplayRepo();
        _mRepo = new MovieRepo();
        _aRepo = new AnimationRepo();
    }

    /** 
     * 首页视频搜索
     */
    void search (HttpRequest req, HttpResponse resp)
    {
        import std.algorithm : canFind;
        import std.string : format;

        string vcate = req.query("vcate");
        string keywords = req.query("keywords");
        string sign = req.query("sign");

        if (vcate is null || vcate == "")
        {
            resp.json(RespData.newData(400, "错误的请求")).send();
            return;
        }
        if (keywords is null || keywords == "")
        {
            resp.json(RespData.newData(400, "错误的请求")).send();
            return;
        }
        if (sign is null || sign == "")
        {
            resp.json(RespData.newData(400, "错误的请求")).send();
            return;
        }

        import std.format : format;

        string reqParamsStr = format("%s%s", vcate, keywords);
        if (!signValidator(reqParamsStr, sign))
        {
            resp.code(HttpStatusCode.FORBIDDEN).json(RespData.newData(403, "签名不正确！")).send();
            return;
        }

        string cachekey = format("%s_%s_%s", CacheKey.SEARCH_RESULT_CACHE, vcate, keywords);
        // 缓存中有数据直接取出返回
        auto data = cacheData.get(cachekey);
        if (!data.isNull)
        {
            resp.json(RespData.newData(200, "ok", data.get)).send();
            return;
        }

        JSONValue respData;
        switch (vcate)
        {
        case "1":
            TeleplayDto[] searchResults = [];
            Teleplay[] list = _tRepo.getTeleplayList();
            foreach (t; list)
            {
                if (canFind(t.name, keywords))
                {
                    searchResults ~= ObjMapping.mappingToObject!(TeleplayDto, Teleplay)(t);
                }
            }
            // 设置缓存
            string jsonData = serializeJson(searchResults);
            cacheData.put(cachekey, jsonData);
            respData = RespData.newData(200, "ok", jsonData);
            break;

        case "2":
            MovieDto[] searchResults = [];
            Movie[] list = _mRepo.getMovieList();
            foreach (m; list)
            {
                if (canFind(m.name, keywords))
                {
                    searchResults ~= ObjMapping.mappingToObject!(MovieDto, Movie)(m);
                }
            }
            // 设置缓存
            string jsonData = serializeJson(searchResults);
            cacheData.put(cachekey, jsonData);
            respData = RespData.newData(200, "ok", jsonData);
            break;

        case "3":
            AnimationDto[] searchResults = [];
            Animation[] list = _aRepo.getAnimationList();
            foreach (a; list)
            {
                if (canFind(a.name, keywords))
                {
                    searchResults ~= ObjMapping.mappingToObject!(AnimationDto, Animation)(a);
                }
            }
            // 设置缓存
            string jsonData = serializeJson(searchResults);
            cacheData.put(cachekey, jsonData);
            respData = RespData.newData(200, "ok", jsonData);
            break;

        default:
            break;
        }

        resp.json(respData).send();
    }
}
